/****************************************************************************/
/* This file is part of FreeFem++.                                          */
/*                                                                          */
/* FreeFem++ is free software: you can redistribute it and/or modify        */
/* it under the terms of the GNU Lesser General Public License as           */
/* published by the Free Software Foundation, either version 3 of           */
/* the License, or (at your option) any later version.                      */
/*                                                                          */
/* FreeFem++ is distributed in the hope that it will be useful,             */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/* GNU Lesser General Public License for more details.                      */
/*                                                                          */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with FreeFem++. If not, see <http://www.gnu.org/licenses/>.        */
/****************************************************************************/
/* SUMMARY : ... */
/* LICENSE : LGPLv3 */
/* ORG     : LJLL Universite Pierre et Marie Curie, Paris, FRANCE */
/* AUTHORS : Pascal Frey */
/* E-MAIL  : pascal.frey@sorbonne-universite.fr
 */

#include "medit.h"
#include "extern.h"
#include "sproto.h"

extern void resetLists (pScene, pMesh);
static int getmesh (pMesh mesh, int range) {
	int ret;
	static char base[256];

	/* allocate mesh structure */
	if (ddebug) fprintf(stdout, "getmesh: create mesh %d\n", range);

	if (mesh->tria) M_free(mesh->tria);

	if (mesh->quad) M_free(mesh->quad);

	if (mesh->edge) M_free(mesh->edge);

	if (mesh->tetra) M_free(mesh->tetra);

	if (mesh->hexa) M_free(mesh->hexa);

	if (mesh->adja) M_free(mesh->adja);

	if (mesh->voy) M_free(mesh->voy);

	if (mesh->point) M_free(mesh->point);

	if (mesh->extra) {
		if (mesh->extra->iv) M_free(mesh->extra->nv);

		if (mesh->extra->it) M_free(mesh->extra->nt);

		if (mesh->extra->iq) M_free(mesh->extra->nq);

		if (mesh->extra->n) M_free(mesh->extra->n);

		M_free(mesh->extra);
		mesh->extra = (void *)0;
	}

	if (mesh->sol && mesh->nbb) {
		if ((mesh->dim == 2 && mesh->nfield == 3) || (mesh->dim == 3 && mesh->nfield == 6)) {
			int k;
			for (k = 1; k <= mesh->nbb; k++) {
				free(mesh->sol[k].m);
			}
		}

		M_free(mesh->sol);
		mesh->sol = (void *)0;
	}

	mesh->point = (void *)0;
	mesh->tria = (void *)0;
	mesh->quad = (void *)0;
	mesh->edge = (void *)0;
	mesh->tetra = (void *)0;
	mesh->hexa = (void *)0;
	mesh->adja = (void *)0;
	mesh->voy = (void *)0;
	mesh->np = mesh->nt = mesh->nq = mesh->ne = 0;
	mesh->ntet = mesh->nhex = mesh->nbb = 0;

	if (animdep == range) {
		/*char *ptr, data[256];
		sprintf(data, ".%d", range);
		ptr = (char *)strstr(mesh->name, data);
		if (ptr) *ptr = '\0';*/

		strcpy(base, mesh->name);
	}

	/* adjust file name */
	sprintf(mesh->name, "%s.%d", base, range);
	if (ddebug) fprintf(stdout, "load %s\n", mesh->name);

	/* read mesh */
	if (quiet) {
		fprintf(stdout, "  Loading %s     \r", mesh->name);
		fflush(stdout);
	}

	mesh->typ = 0;
	ret = loadMesh(mesh);
	if (ret < 1) {
		mesh->typ = 1;
		ret = inmsh2(mesh);
		if (!ret) {
			mesh->typ = 2;
			ret = loadGIS(mesh);
			if (!ret) return (0);
		}
	}

	if ((mesh->ntet && !mesh->nt) || (mesh->nhex && !mesh->nq))
		meshSurf(mesh);

	meshBox(mesh, animdep == range);
	if (!quiet) meshInfo(mesh);

	/* read metric */
	if (!loadSol(mesh, mesh->name, 1))
		bbfile(mesh);

	if (!quiet && mesh->nbb)
		fprintf(stdout, "    Solutions  %8d\n", mesh->nbb);

	return (1);
}

int loadNextMesh (pMesh mesh, int k, int parse) {
	pScene sc;
	int is;

	if (!getmesh(mesh, k)) return (0);

	if (ddebug) printf("loadNextMesh: create %d window(s)\n", cv.nbs);

	/* compute mesh box */
	is = currentScene();
	if (!cv.scene[is]) {
		cv.scene[is] = (pScene)M_calloc(1, sizeof(Scene), "loadNextMesh.scene");
		if (!cv.scene[is]) return (0);
	}

	sc = cv.scene[is];
	if (parse)
		parsop(sc, mesh);

	setupPalette(sc, mesh);
	meshRef(sc, mesh);
	matSort(sc);

	return (1);
}

int playAnim (pScene sc, pMesh mesh, int deb, int fin) {
	int k;
	char *ptr, data[256], base[256];

	/* get basename */
	sprintf(data, ".%d", deb);
	ptr = (char *)strstr(mesh->name, data);
	if (ptr) *ptr = '\0';

	strcpy(base, mesh->name);

	if (saveimg)
		glDrawBuffer(GL_BACK_LEFT);

	/* start animation */
	for (k = deb; k <= fin; k++) {
		strcpy(mesh->name, base);

		resetLists(sc, mesh);
		if (!loadNextMesh(mesh, k, 0)) return (0);

		doLists(sc, mesh);
		sc->glist = geomList(sc, mesh);
		if (sc->mode & S_MAP) doMapLists(sc, mesh, 1);

		if (sc->isotyp) doIsoLists(sc, mesh, 1);

		if (!saveimg) {
			sprintf(data, "Medit - [%s] #%d", mesh->name, sc->idwin);
			glutSetWindowTitle(data);
		}

		glClearColor(sc->par.back[0], sc->par.back[1], sc->par.back[2], sc->par.back[3]);
		if (sc->type & S_SCISSOR)
			scissorScene();
		else
			redrawScene();
	}

	fprintf(stdout, "\n  Done.\n");
	strcpy(mesh->name, base);

	if (saveimg) {
		glDrawBuffer(GL_FRONT | GL_BACK);
		if (saveimg) {
			sprintf(data, "Medit - [%s] #%d", mesh->name, sc->idwin);
			glutSetWindowTitle(data);
		}

		glutPostRedisplay();
		saveimg = 0;
	}

	return (1);
}

int animParticle (pScene sc, pMesh mesh) {
	int cur;
	char *ptr, data[256], base[256];

	/* get basename */
	strcpy(base, mesh->name);
	ptr = (char *)strstr(base, ".");
	sscanf(ptr, ".%d", &cur);
	cur++;
	if (cur > animfin) return (0);

	if (ptr) ptr[0] = '\0';

	sprintf(data, "%s.%.3d", base, cur);
	strcpy(mesh->name, base);

	resetLists(sc, mesh);
	if (!loadNextMesh(mesh, cur, 1)) return (0);

	doLists(sc, mesh);
	sc->glist = geomList(sc, mesh);
	if (sc->mode & S_MAP) doMapLists(sc, mesh, 1);

	if (sc->isotyp) doIsoLists(sc, mesh, 2);

	if (!advectParticle(sc, mesh)) return (0);

	return (1);
}

int animat () {
	pMesh mesh;
	pScene sc;

	/* default */
	if (ddebug) printf("animat: read file(s)\n");

	/* enter basename */
	if (!cv.nbm) {
		char data[128], *name;
		
		fprintf(stdout, "  File name(s) missing. Please enter : ");
		fflush(stdout);
		while(fgetc(stdin)!=EOF);	//fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux systems
		fgets(data, 120, stdin);
		if (!strlen(data)) {
			fprintf(stdout, "  ## Error\n");
			return (0);
		}

		fprintf(stdout, "  Enter range [start,end] :");
		fflush(stdout);
		while(fgetc(stdin)!=EOF);	//fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux systems
		fscanf(stdin, "%d %d", &animdep, &animfin);

		/* parse file name(s) */
		name = strtok(data, " \n");

		while (name) {
			if (!cv.mesh[cv.nbm]) {
				cv.mesh[cv.nbm] = (pMesh)M_calloc(1, sizeof(Mesh), "animat.mesh");
				if (!cv.mesh[cv.nbm]) return (0);
			}

			/*(cv.mesh[cv.nbm])->name = calloc(strlen(name)+15,sizeof(char));*/
			strcpy(cv.mesh[cv.nbm]->name, name);
			break;
		}

		if (!cv.nbm) return (0);
	}

	cv.nbs = cv.nbm;

	/* read initial mesh */
	mesh = cv.mesh[0];
	if (!loadNextMesh(mesh, animdep, 1)) return (0);

	/* create grafix */
	sc = cv.scene[0];
	if (!createScene(sc, 0)) {
		fprintf(stderr, "  ## Unable to create scene\n");
		return (0);
	}

	quiet = 1;
	return (1);
}
